#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'wshu'
__version__ = '1.0'
"""
    ***********************************
    *  @filename : task.py
    *  @Author : wshu
    *  @CodeDate : 2020/3/25 14:23
    *  @Software : PyCharm
    ***********************************
"""
import time
import tornado.escape
from datetime import datetime, timedelta
from core import BaseHandlers
from core.hostscan.utils import get_ip_for_host
from core.comm.utils.timezone import now as timezone
from db.mysql import Task, Site
from db.mysql import Ai_detec_conf
from db.mysql import TextStor, ImageStor
from db.mysql import Strategy
from sqlalchemy import func, and_, or_, desc, cast, Numeric, DATE, distinct, extract
from core.comm.http.JsonResponse import Jsonify, JsonForm
from Ui.HFmSetting.utils.functional import paging
from Ui.HFmSetting.utils.checktool import check_task_name

class TaskViewHandler(BaseHandlers):
    """
    站点任务视图
    """
    error_msg = ''

    def get(self, *args, **kwargs):
        self.render('tasks/task_list.html', error_msg=self.error_msg)

class TaskListHandler(BaseHandlers):
    """
    站点任务监测列表
    TASK_STATUS = {
        '0': '待执行',
        '1': '执行中',
        '2': '已完成',
        '3': '已结束',
    }
    """
    error_msg = ''

    TASK_STATUS = {
        '0': '待执行',
        '1': '执行中',
        '2': '已完成',
        '3': '已结束',
    }
    @staticmethod
    def get_count(Q):
        count_query = Q.statement.with_only_columns([func.count()]).order_by(None)
        count = Q.session.execute(count_query).scalar()
        return count

    def post(self, *args, **kwargs):
        """
        任务列表展示
        """
        page = self.get_argument('page', None)
        rows = self.get_argument('limit', None)
        taskname = self.get_argument('taskname', None)
        status = self.get_argument('status', None)

        if not taskname:
            taskname = ''

        if not status:
            status = ['0', '1', '2', '3']
        else:
            status = status

        # 分页查询 p: 页 r: 条
        p, r = paging(page, rows)
        # 按任务名查询
        task_obj = self.db.query(Task).filter(or_(Task.task_name.like(taskname),
                                                  or_(Task.task_status.in_(status))))

        task_list = task_obj.order_by(desc(Task.create_at)).slice(p, r).all()
        # 查询24小时数据
        # near24 = self.get_count(self.db.query(Task).filter(and_(Task.create_at.between(timezone() - timedelta(seconds=24*3600-1), timezone())),
        #                                                    Task.id == 2))
        # print("近24小时爬取量：", near24)
        # 任务站点数量
        # FIXME: 统计文本、图片爬取总量需要优化查询速度
        # FIXME: 统计文本、图片近24小时内爬取总量存在问题
        total = self.get_count(task_obj)
        laydata = []
        for task_item in task_list:
            tempDict = {}
            tempDict['taskname'] = task_item.task_name
            tempDict['sitenum'] = self.get_count(self.db.query(Site).filter_by(task_id=task_item.id))
            tempDict['near24h'] = self.get_count(self.db.query(TextStor).filter(and_(TextStor.grab_time.between(timezone() - timedelta(seconds=24*3600-1), timezone())),
                                                           TextStor.task_id == task_item.id))
            tempDict['countnum'] = self.get_count(self.db.query(TextStor, ImageStor).filter_by(task_id=task_item.id))
            tempDict['creatname'] = 'admin'
            tempDict['creat_at'] = task_item.create_at.strftime("%Y-%m-%d %H:%M:%S")
            if task_item.task_status == '0':
                tempDict['status'] = '待执行'
            elif task_item.task_status == '1':
                tempDict['status'] = '执行中'
            elif task_item.task_status == '2':
                tempDict['status'] = '已完成'
            elif task_item.task_status == '3':
                tempDict['status'] = '已结束'

            laydata.append(tempDict)

        # print(">>>: ", laydata)
        # 以JSON形式返回数据
        json_data = Jsonify(
            code=0,
            msg="任务列表",
            count=total,
            data=laydata).json()
        self.write(json_data)

    def put(self, *args, **kwargs):
        """
        任务开启和编辑
        """
        task_name = self.get_argument('taskname', None)
        task_status = self.get_argument('status', None)
        action = self.get_argument('action', None)
        # 任务开启更改状态
        if action == 'start':
            status = list(self.TASK_STATUS.keys())[list(self.TASK_STATUS.values()).index(self.TASK_STATUS['1'])]
            self.db.query(Task).filter(Task.task_name == task_name).update({Task.task_status: status})
            self.db.commit()
            # 返回状态
            self.error_msg = JsonForm(status='success', msg='任务已开启').Dict
            self.write(self.error_msg)
        else:
            self.error_msg = JsonForm(status='error', msg='操作失败').Dict
            self.write(self.error_msg)

    def delete(self, *args, **kwargs):
        """
        任务删除
        """
        task_str = self.get_argument('task_list', None)
        action = self.get_argument('action', None)
        task_list = tornado.escape.json_decode(task_str)
        if action == 'start':
            for task_item in task_list:
                self.db.query(Task).filter(Task.task_name == task_item).delete()
            self.db.commit()
            self.error_msg = JsonForm(status='success', msg='删除成功').Dict
        else:
            if action == 'stop':
                pass
        self.write(self.error_msg)

class TaskAddHandler(BaseHandlers):
    """
    站点添加，考虑每个任务的监测策略不同，
    将用户创建的站点任务监测配置策略统一结构化处理
    """
    error_msg = ''

    def get(self, *args, **kwargs):
        keyword_strategy_list = self.db.query(Strategy).all()
        self.render('tasks/task_add.html', error_msg=self.error_msg,
                    keyword_strategy_list=keyword_strategy_list)

    def post(self, *args, **kwargs):
        """
        # 任务依据策略定义，每个任务的策略不同，规范任务策略形式
        # [{'图片检测': [涉黄，涉政，涉毒，反腐]}, '文本检测': [], '关键词': [涉黄，涉毒，自定义，自定义1，...]]
        """
        CONF_MODE = {
            1: u'文本',
            2: u'图片',
            3: u'关键词'}
        try:
            latest_id = self.db.query(Task).filter(Task.id == self.db.query(func.max(Task.id))).first().id
        except AttributeError:
            latest_id = 0
        latest_id += 1
        task_id = str('t') + time.strftime('%Y%m%d', time.localtime(time.time())) + str(latest_id)
        task_name = self.get_argument('taskname', None)
        site_str = self.get_argument('site_list', None)
        text_strategy = self.get_argument('strategy_text', None)
        image_strategy = self.get_argument('strategy_img', None)
        keyword_strategy = self.get_argument('strategy_kw', None)

        # 检查输入任务名称是否合规
        if check_task_name(task_name):
            # 检查任务是否存在
            is_task_exists = self.db.query(Task).filter_by(task_name=task_name).first()
            if not is_task_exists:
                # 对任务配置策略进行结构化处理
                strategy_conf = {}
                if text_strategy:
                    strategy_conf[CONF_MODE[1]] = text_strategy
                if image_strategy:
                    strategy_conf[CONF_MODE[2]] = image_strategy
                if keyword_strategy:
                    strategy_conf[CONF_MODE[3]] = keyword_strategy
                # 任务存储
                task_get = Task(
                    task_id=task_id,
                    task_name=task_name,
                    task_plan='单次',
                    task_type='内容监测',
                    task_status='0',
                    user_id=1,
                    create_at=timezone()
                )
                self.db.add(task_get)
                self.db.flush()
                taskId = task_get.id

                # 检测策略配置存储，conf_mode: 采用什么方式检测 conf_type: 具体检测的类型
                # 存储实例: {'id': 1, 'conf_mode': 'text_conf', 'conf_type': '涉黄,涉政,涉毒,涉赌,反腐,民生'}
                # FIXME: 策略存储结构可能存在耦合问题？？
                conf_get = [Ai_detec_conf(
                    conf_mode=conf_mode,
                    conf_type=conf_type,
                    create_at=timezone(),
                    user_id=1,
                    task_id=taskId,
                ) for conf_mode, conf_type in strategy_conf.items()]
                # print("conf_get: ", conf_get)
                self.db.bulk_save_objects(conf_get)
                self.db.flush()
                # FIXME 做统计时候可能需要
                # 任务下站点存储
                site_str_tab = site_str.replace(' ', '')
                site_get_list = site_str_tab.split('\n')
                site_list = [site_name if site_name.startswith('http') else 'http://' + site_name for site_name in site_get_list]
                while "" in site_list: site_list.remove("")
                # FIXME: site_ip在这里用socket获取会增加站点数据入库时长
                # get_ip_for_host(site_name)
                site_get = [Site(
                    site_name=site_name,
                    site_ip='',
                    status='0',
                    task_id=taskId,
                    user_id=1
                ) for site_name in site_list]
                # print("site_get: ", site_get)
                self.db.bulk_save_objects(site_get)
                self.db.commit()
                self.error_msg = '任务添加成功，'
                # 添加成功返回
                self.error_msg = JsonForm(status='success', msg="任务添加成功").Dict
            else:
                self.error_msg = JsonForm(status='error', msg="添加失败，该任务名称已存在").Dict
        else:
            self.error_msg = JsonForm(status='error', msg="禁止非法输入哦，任务名长度不超过20，支持中文、字母、数字、下划线").Dict
        self.write(self.error_msg)


class TaskDeleteHandler(BaseHandlers):
    """
    单任务删除
    FIXME: 批量删除也同时在这里处理
    """
    def post(self, *args, **kwargs):
        self.write('ok')